﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Common.CommandTrees;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Web.Http;
using WordsOfLoveServer.Models;
using WordsOfLoveServer.Models.Forums;
using WordsOfLoveServer.Models.ReturnValues;

namespace WordsOfLoveServer.Controllers
{
    public class ForumPostController : ApiController
    {
		#region Post APIs (GET APIs)
		// GET: api/ForumPost/GetPostsByTitle?title=xxx
		[HttpGet]
		public HttpResponseMessage GetPostsByTitle(string title)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					IQueryable<ForumPost> postQuery = db.ForumPosts;
					if (title != null) postQuery = postQuery.Where(post => post.Title.Contains(title));
					List<ForumPost> rawPosts = postQuery.ToList();
					List<ForumPostInfo> posts = new List<ForumPostInfo>();
					foreach(ForumPost post in rawPosts)
					{
						posts.Add(new ForumPostInfo(post)
						{
							CommentCount =
								(from comment in db.ForumComments
								 where comment.PostId == post.Id
								 select comment).Count(),
							LikeCount =
								(from like in db.ForumPostLikes
								 where like.PostId == post.Id
								 select like).Count(),
							UserName = db.Users.Find(post.UserId).UserName
						});
					}
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(posts))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// GET: api/ForumPost/GetPostsByTag?tag=xxx
		[HttpGet]
		public HttpResponseMessage GetPostsByTag(string tag)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					IQueryable<ForumPost> postQuery = db.ForumPosts;
					if (tag != null)
					{
						postQuery =
							from x in db.ForumPosts
							join y in db.ForumPostTags
							on x.Id equals y.PostId
							where y.Content == tag
							select x;
					}
					List<ForumPost> rawPosts = postQuery.ToList();
					List<ForumPostInfo> posts = new List<ForumPostInfo>();
					foreach (ForumPost post in rawPosts)
					{
						posts.Add(new ForumPostInfo(post)
						{
							CommentCount =
								(from comment in db.ForumComments
								 where comment.PostId == post.Id
								 select comment).Count(),
							LikeCount =
								(from like in db.ForumPostLikes
								 where like.PostId == post.Id
								 select like).Count(),
							UserName = db.Users.Find(post.UserId).UserName
						});
					}
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(posts.ToList()))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// GET: api/ForumPost/GetPostsByUserName?username=xxx
		[HttpGet]
		public HttpResponseMessage GetPostsByUserName(string username)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					IQueryable<ForumPost> postQuery = db.ForumPosts;
					if (username != null)
					{
						postQuery =
							from x in db.ForumPosts
							join y in db.Users
							on x.UserId equals y.Id
							where y.UserName.Contains(username)
							select x;
					}
					List<ForumPost> rawPosts = postQuery.ToList();
					List<ForumPostInfo> posts = new List<ForumPostInfo>();
					foreach (ForumPost post in rawPosts)
					{
						posts.Add(new ForumPostInfo(post)
						{
							CommentCount =
								(from comment in db.ForumComments
								 where comment.PostId == post.Id
								 select comment).Count(),
							LikeCount =
								(from like in db.ForumPostLikes
								 where like.PostId == post.Id
								 select like).Count(),
							UserName = db.Users.Find(post.UserId).UserName
						});
					}
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(posts.ToList()))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// GET: api/ForumPost/GetPostsByUserId?id=xxx
		[HttpGet]
		public HttpResponseMessage GetPostsByUserId(int id)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					IQueryable<ForumPost> postQuery =
							from x in db.ForumPosts
							where x.UserId == id
							select x;
					List<ForumPost> rawPosts = postQuery.ToList();
					List<ForumPostInfo> posts = new List<ForumPostInfo>();
					foreach (ForumPost post in rawPosts)
					{
						posts.Add(new ForumPostInfo(post)
						{
							CommentCount =
								(from comment in db.ForumComments
								 where comment.PostId == post.Id
								 select comment).Count(),
							LikeCount =
								(from like in db.ForumPostLikes
								 where like.PostId == post.Id
								 select like).Count(),
							UserName = db.Users.Find(post.UserId).UserName
						});
					}
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(posts.ToList()))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// GET: api/ForumPost/GetRecentPosts
		[HttpGet]
		public HttpResponseMessage GetRecentPosts()
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					IQueryable<ForumPost> postQuery = db.ForumPosts.OrderByDescending(x => x.CreateTime).Take(50);
					List<ForumPost> rawPosts = postQuery.ToList();
					List<ForumPostInfo> posts = new List<ForumPostInfo>();
					foreach (ForumPost post in rawPosts)
					{
						posts.Add(new ForumPostInfo(post)
						{
							CommentCount =
								(from comment in db.ForumComments
								 where comment.PostId == post.Id
								 select comment).Count(),
							LikeCount =
								(from like in db.ForumPostLikes
								 where like.PostId == post.Id
								 select like).Count(),
							UserName = db.Users.Find(post.UserId).UserName
						});
					}
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(posts.ToList()))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// GET: api/ForumPost/GetHotPosts
		[HttpGet]
		public HttpResponseMessage GetHotPosts()
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					IQueryable<ForumPost> postQuery =
						from post in db.ForumPosts
						join like in db.ForumPostLikes
						on post.Id equals like.PostId into plg
						from plgi in plg.DefaultIfEmpty()
						group plgi by post into g
						orderby g.Count() descending
						select g.Key;
					List<ForumPost> rawPosts = postQuery.ToList();
					List<ForumPostInfo> posts = new List<ForumPostInfo>();
					foreach (ForumPost post in rawPosts)
					{
						posts.Add(new ForumPostInfo(post)
						{
							CommentCount =
								(from comment in db.ForumComments
								 where comment.PostId == post.Id
								 select comment).Count(),
							LikeCount =
								(from like in db.ForumPostLikes
								 where like.PostId == post.Id
								 select like).Count(),
							UserName = db.Users.Find(post.UserId).UserName
						});
					}
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(posts.Take(100).ToList()))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// GET: api/ForumPost/GetAllPosts
		[HttpGet]
		public HttpResponseMessage GetAllPosts()
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					IQueryable<ForumPost> postQuery = db.ForumPosts;
					List<ForumPost> rawPosts = postQuery.ToList();
					List<ForumPostInfo> posts = new List<ForumPostInfo>();
					foreach (ForumPost post in rawPosts)
					{
						posts.Add(new ForumPostInfo(post)
						{
							CommentCount =
								(from comment in db.ForumComments
								 where comment.PostId == post.Id
								 select comment).Count(),
							LikeCount =
								(from like in db.ForumPostLikes
								 where like.PostId == post.Id
								 select like).Count(),
							UserName = db.Users.Find(post.UserId).UserName
						});
					}
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(posts.ToList()))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// GET: api/ForumPost/GetPostById?id=xxx
		[HttpGet]
		public HttpResponseMessage GetPostById(int id)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					ForumPost post = db.ForumPosts.Find(id);
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(post))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}
		#endregion

		#region Post APIs (Other APIs)

		// POST: api/ForumPost/CreatePost
		[HttpPost]
		public HttpResponseMessage CreatePost([FromBody] ForumPost post)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					db.ForumPosts.Add(post);
					db.SaveChanges();
				}
				return new HttpResponseMessage(HttpStatusCode.Created)
				{
					Content = new StringContent(JsonConvert.SerializeObject(post))
				};
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// PUT: api/ForumPost/UpdatePost
		[HttpPut]
		public HttpResponseMessage UpdatePost([FromBody] ForumPost post)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					db.Entry(post).State = EntityState.Modified;
					db.SaveChanges();
				}
				return new HttpResponseMessage(HttpStatusCode.OK);
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		//DELETE: api/ForumPost/DeletePost?id=xxx
		[HttpDelete]
		public HttpResponseMessage DeletePost(int id)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					ForumPost post = db.ForumPosts.Find(id);
					if (post == null)
					{
						return new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent("Item doesn't exist.") };
					}
					db.ForumPosts.Remove(post);
					db.SaveChanges();
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
			return new HttpResponseMessage(HttpStatusCode.OK);
		}

		#endregion

		#region PostTag APIs
		// GET: api/ForumPost/GetTags?postId=xxx
		[HttpGet]
		public HttpResponseMessage GetTags(int postId)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					List<ForumPostTag> tags = db.ForumPostTags.Where(x => x.PostId == postId).ToList();
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(tags))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// PUT: api/ForumPost/CreateTag
		[HttpPut]
		public HttpResponseMessage CreateTag(ForumPostTag tag)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					db.ForumPostTags.Add(tag);
					db.SaveChanges();
				}
				return new HttpResponseMessage(HttpStatusCode.Created);
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// DELETE: api/ForumPost/DeleteTag?postId=xxx&tag=xxx
		[HttpDelete]
		public HttpResponseMessage DeleteTag(int postId, string tag)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					ForumPostTag tagToBeDeleted = db.ForumPostTags.Find(postId, tag);
					db.ForumPostTags.Remove(tagToBeDeleted);
					db.SaveChanges();
				}
				return new HttpResponseMessage(HttpStatusCode.OK);
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// DELETE: api/ForumPost/DeleteAllTag?postId=xxx
		[HttpDelete]
		public HttpResponseMessage DeleteAllTag(int postId)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					List<ForumPostTag> tagToBeDeleted = db.ForumPostTags.Where(x => x.PostId == postId).ToList();
					db.ForumPostTags.RemoveRange(tagToBeDeleted);
					db.SaveChanges();
				}
				return new HttpResponseMessage(HttpStatusCode.OK);
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}
		#endregion

		#region PostLike APIS
		// GET: api/ForumPost/GetLikeCount?postId=xxx
		[HttpGet]
		public HttpResponseMessage GetLikeCount(int postId)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					int count = db.ForumPostLikes.Where(x => x.PostId == postId).Count();
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(count))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// GET: api/ForumPost/GetLike?postId=xxx&userId=xxx
		[HttpGet]
		public HttpResponseMessage GetLike(int postId, int userId)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					ForumPostLike like = db.ForumPostLikes.Find(userId, postId);
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(like))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// PUT: api/ForumPost/CreateLike
		[HttpPut]
		public HttpResponseMessage CreateLike([FromBody] ForumPostLike like)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					db.ForumPostLikes.Add(like);
					db.SaveChanges();
				}
				return new HttpResponseMessage(HttpStatusCode.Created);
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// DELETE: api/ForumPost/DeleteLike?postId=xxx&userId=xxx
		[HttpDelete]
		public HttpResponseMessage DeleteLike(int postId, int userId)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					db.ForumPostLikes.Remove(db.ForumPostLikes.Find(userId, postId));
					db.SaveChanges();
				}
				return new HttpResponseMessage(HttpStatusCode.OK);
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		#endregion
	}

	public class ForumCommentController : ApiController
	{
		#region PostComment APIs
		// GET: api/ForumComment/GetComments?postId=xxx
		[HttpGet]
		public HttpResponseMessage GetComments(int postId)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					IQueryable<ForumComment> commentQuery = db.ForumComments.Where(x => x.PostId == postId);
					List<ForumComment> rawComments = commentQuery.ToList();
					List<ForumCommentInfo> comments = new List<ForumCommentInfo>();
					foreach (ForumComment comment in rawComments)
					{
						comments.Add(new ForumCommentInfo(comment)
						{
							LikeCount =
								(from like in db.ForumCommentLikes
								 where like.CommentId == comment.Id
								 select like).Count(),
							UserName = db.Users.Find(comment.UserId).UserName
						});
					}
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(comments.ToList()))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// GET: api/ForumComment/GetCommentCount?postId=xxx
		[HttpGet]
		public HttpResponseMessage GetCommentCount(int postId)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					int count = db.ForumComments.Where(x => x.PostId == postId).Count();
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(count))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// POST: api/ForumComment/CreateComment
		[HttpPost]
		public HttpResponseMessage CreateComment([FromBody] ForumComment comment)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					db.ForumComments.Add(comment);
					db.SaveChanges();
				}
				return new HttpResponseMessage(HttpStatusCode.Created)
				{
					Content = new StringContent(JsonConvert.SerializeObject(comment))
				};
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// PUT: api/ForumComment/UpdateComment
		[HttpPut]
		public HttpResponseMessage UpdateComment([FromBody] ForumComment comment)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					db.Entry(comment).State = EntityState.Modified;
					db.SaveChanges();
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
			return new HttpResponseMessage(HttpStatusCode.OK);
		}

		// DELETE: api/ForumComment/DeleteComment/xxx
		[HttpDelete]
		public HttpResponseMessage DeleteComment(int id)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					ForumComment comment = db.ForumComments.Find(id);
					if (comment == null)
					{
						return new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent("Item doesn't exist.") };
					}
					db.ForumComments.Remove(comment);
					db.SaveChanges();
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
			return new HttpResponseMessage(HttpStatusCode.OK);
		}

		#endregion

		#region PostCommentLike APIs
		// GET: api/ForumComment/GetLikeCount?commentId=xxx
		[HttpGet]
		public HttpResponseMessage GetLikeCount(int commentId)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					int count = db.ForumCommentLikes.Where(x => x.CommentId == commentId).Count();
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(count))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// GET: api/ForumComment/GetLike?postId=xxx&userId=xxx
		[HttpGet]
		public HttpResponseMessage GetLike(int commentId, int userId)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					ForumCommentLike like = db.ForumCommentLikes.Find(userId, commentId);
					return new HttpResponseMessage()
					{
						RequestMessage = Request,
						Content = new StringContent(JsonConvert.SerializeObject(like))
					};
				}
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// PUT: api/ForumComment/CreateLike
		[HttpPut]
		public HttpResponseMessage CreateLike([FromBody] ForumCommentLike like)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					db.ForumCommentLikes.Add(like);
					db.SaveChanges();
				}
				return new HttpResponseMessage(HttpStatusCode.Created);
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}

		// DELETE: api/ForumComment/DeleteLike?postId=xxx&userId=xxx
		[HttpDelete]
		public HttpResponseMessage DeleteLike(int commentId, int userId)
		{
			try
			{
				using (var db = new WOLDbContext())
				{
					db.ForumCommentLikes.Remove(new ForumCommentLike() { CommentId = commentId, UserId = userId });
					db.SaveChanges();
				}
				return new HttpResponseMessage(HttpStatusCode.OK);
			}
			catch (Exception ex)
			{
				return new HttpResponseMessage(HttpStatusCode.BadRequest)
				{
					Content = new StringContent(ex.Message)
				};
			}
		}
		#endregion
	}
}
